其他
Android死锁初探
点击蓝字关注我们
本文字数:7444字
预计阅读时间:19分钟
一、什么是死锁
集合中的每一个进程(或线程)都在等待只能由本集合中的其他进程(或线程)才能引发的事件,那么该组进程是死锁的。
死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
二、常见的死锁的场景
🔺锁顺序死锁
public class TestDeadLock {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void lockAtoB(){
synchronized (lockA){
synchronized (lockB){
doSomething();
}
}
}
public void lockBtoA(){
synchronized (lockB){
synchronized (lockA){
doSomething();
}
}
}
private void doSomething(){
System.out.println("doSomething");
}
}
//仓库
public static interface IStore{
public void inCome(int count);
public void outCome(int count);
}
/**
* 从 in 仓库 调用货物去 out仓库
* @param from
* @param to
* @param count 调用货物量
*/
public void transportGoods(IStore from,IStore to,int count){
synchronized (from){
synchronized (to){
from.outCome(count);//出仓库
to.inCome(count);//入仓库
}
}
}
transportGoods(storeA,storeB,100);
transportGoods(storeB,storeA,40);
private static final Object extraLock = new Object();
/**
* 从 in 仓库 调用货物去 out仓库
* @param from
* @param to
* @param count 调用货物量
*/
public void transportGoods(IStore from,IStore to,int count){
int fromHashCode = System.identityHashCode(from);
int toHashCode = System.identityHashCode(to);
if(fromHashCode > toHashCode){
synchronized (from){
synchronized (to){
transportGoodsInternal(from,to,count);
}
}
}else if(fromHashCode < toHashCode){
synchronized (to){
synchronized (from){
transportGoodsInternal(from,to,count);
}
}
}else {//hash散列冲突,需要用新的一个锁来保证这种低概率情况下不出现问题
synchronized (extraLock){
synchronized (from){
synchronized (to){
transportGoodsInternal(from,to,count);
}
}
}
}
}
public void transportGoodsInternal(IStore from,IStore to,int count){
from.outCome(count);//出仓库
to.inCome(count);//入仓库
}
需要注意的是,使用hashcode这种方式是兼容性最好,成本最低也最不容易出错的方式,如果使用自有编码,你需要确保编码的唯一性,不可变性,这要保证这一点很不容易。
🔺多个对象协作发生的死锁
/**
* 玩游戏者
*/
class Player {
private SystemMonitor monitor;
private int cardCount;//收集的卡片的数量
public Player(SystemMonitor monitor) {
this.monitor = monitor;
}
public synchronized int getCardCount() {
return cardCount;
}
public synchronized void collectCard(int count){
cardCount += count;
if(cardCount >= 50){
monitor.notifyComplete(this);
}
}
}
/**
* 监控系统
*/
class SystemMonitor {
private ArrayList<Player> playerArrayList;//所有玩家
private ArrayList<Player> completePlayerArrayList = new ArrayList<>();//完成的玩家
//通知监控系统完成
public synchronized void notifyComplete(Player player){
System.out.println("玩家完成收集");
completePlayerArrayList.add(player);
}
//实时监控大家手中牌的数量
public synchronized void monitorAllPlayer(){
for (Player player : playerArrayList){
System.out.println("玩家有"+ player.getCardCount() + "张牌");
}
}
}
当一个对象的方法在持有锁期间调用外部方法,这时应该格外注意,因为无法显式判断外部方法是否有其他锁,而这样就有可能产生死锁。
public void collectCard(int count){
boolean isComplete = false;
synchronized (this){
cardCount += count;
if(cardCount >= 50){
isComplete = true;
}
}
if(isComplete){
monitor.notifyComplete(this);
}
}
//实时监控大家手中牌的数量
public void monitorAllPlayer(){
ArrayList<Player> copy;
synchronized (this){
copy = new ArrayList<>(playerArrayList);
}
for (Player player : copy){
System.out.println("玩家有"+ player.getCardCount() + "张牌");
}
}
🔺线程饥饿死锁
private ThreadPoolExecutor executor = new ThreadPoolExecutor(5,5,0,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());;
@Test
public void test() throws ExecutionException, InterruptedException {
int count = 0;
while (true) {
System.out.println("开始 = " + (count));
start();
System.out.println("结束 = " + (count++));
Thread.sleep(10);
}
}
public void start() throws ExecutionException, InterruptedException {
Callable<String> second = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(100);
return "second callable";
}
};
Callable<String> first = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(10);
Future<String> secondFuture = executor.submit(second);
String secondResult = secondFuture.get();
Thread.sleep(10);
return "first callable. second result = " + secondResult;
}
};
List<Future<String>> futures = new ArrayList<>();
for(int i = 0; i< 5; i++){
System.out.println("submit : " + i);
Future<String> firstFuture = executor.submit(first);
futures.add(firstFuture);
}
for(int i = 0; i < 5; i++){
String firstrResult = futures.get(i).get();
System.out.println(firstrResult + ":" + i);
}
}
三、Android系统处理死锁方案
定期轮询检测系统中核心的线程的状态 检测到卡死后,将相关对应的线程,进程及其他软硬件信息输出
public void run() {
boolean waitedHalf = false;
while (true) {//我们要在Android系统运行的整个过程中监控,当然我们需要一个死循环
final List<HandlerChecker> blockedCheckers;
final String subject;
final boolean allowRestart;
int debuggerWasConnected = 0;
synchronized (this) {
long timeout = CHECK_INTERVAL;
//代码关键点1
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
hc.scheduleCheckLocked();
}
....
//代码关键点2
long start = SystemClock.uptimeMillis();
while (timeout > 0) {
...
try {
wait(timeout);
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
...
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
}
...
//代码关键点3
boolean fdLimitTriggered = false;
if (mOpenFdMonitor != null) {
fdLimitTriggered = mOpenFdMonitor.monitor();
}
//代码关键点4
if (!fdLimitTriggered) {
final int waitState = evaluateCheckerCompletionLocked();
if (waitState == COMPLETED) {
waitedHalf = false;
continue;
} else if (waitState == WAITING) {
continue;
} else if (waitState == WAITED_HALF) {
if (!waitedHalf) {
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
ActivityManagerService.dumpStackTraces(true, pids, null, null,
getInterestingNativePids());
waitedHalf = true;
}
continue;
}
blockedCheckers = getBlockedCheckersLocked();
subject = describeCheckersLocked(blockedCheckers);
} else {
blockedCheckers = Collections.emptyList();
subject = "Open FD high water mark reached";
}
allowRestart = mAllowRestart;
}
//代码关键点5
//代码运行到这里,说明系统已经卡死
final File stack = ActivityManagerService.dumpStackTraces(
!waitedHalf, pids, null, null, getInterestingNativePids());
doSysRq('w');
doSysRq('l');
...
IActivityController controller;
if (controller != null) {
...
int res =controller.systemNotResponding(subject);
if (res >= 0) {
...
continue;
}
}
// 代码关键点6
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
if (debuggerWasConnected >= 2) {
} else if (debuggerWasConnected > 0) {
} else if (!allowRestart) {
} else {//只有这种情况下,杀死system_server
...
//代码关键点6
Process.killProcess(Process.myPid());
System.exit(10);
}
waitedHalf = false;
}
}
private Watchdog() {
super("watchdog");
...
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
"foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
"main thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
"ui thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
"i/o thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));
addMonitor(new BinderThreadMonitor());
mOpenFdMonitor = OpenFdMonitor.create();//这个monitor有额外作用,后面我们会有提到
...
}
public void addMonitor(Monitor monitor) {
....
mMonitorChecker.addMonitor(monitor);
}
}
public final class HandlerChecker implements Runnable {
...
private final Handler mHandler;
private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
private boolean mCompleted;
...
public void scheduleCheckLocked() {
if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {//特殊的条件,需要注意,下面有解释
mCompleted = true;
return;
}
if (!mCompleted) {
return;
}
mCompleted = false;
mCurrentMonitor = null;
mStartTime = SystemClock.uptimeMillis();
mHandler.postAtFrontOfQueue(this);
}
...
@Override
public void run() {
final int size = mMonitors.size();
for (int i = 0 ; i < size ; i++) {
synchronized (Watchdog.this) {
mCurrentMonitor = mMonitors.get(i);
}
mCurrentMonitor.monitor();
}
synchronized (Watchdog.this) {
mCompleted = true;
mCurrentMonitor = null;
}
}
}
private int evaluateCheckerCompletionLocked() {
int state = COMPLETED;
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
state = Math.max(state, hc.getCompletionStateLocked());
}
return state;
}
debuggerWasConnected>=0 debuggerWasConnected>=2 代表debugger正在连接调试中 allowRestart设置为true,是通过adb logcat am hang命令设置的
四、Android开发过程中死锁分析方法
借助ANR机制
adb shell ps | grep com.sohu.sohuvideo
adb shell run-as com.sohu.sohuvideo kill -3 22841
adb shell cat /data/anr/dumptrace_YbVvLP > ~/Desktop/dump
结束语
参考资料
《System.identityHashCode(obj) 与 obj.hashcode()》(https://www.jianshu.com/p/24fa4bdb9b9d)
也许你还想看
(▼点击文章标题或封面查看)
加入搜狐技术作者天团
千元稿费等你来!
戳这里!☛